package com.dashu.core.service;

import com.dashu.base.enums.ReplRyCode;
import com.dashu.base.enums.device.*;
import com.dashu.base.enums.school.Position;
import com.dashu.base.redis.JedisUtil;
import com.dashu.base.redis.RedisLiveKeyConstants;
import com.dashu.base.utils.CopyUtil;
import com.dashu.base.utils.UIDUtil;
import com.dashu.base.utils.VerificationUtil;
import com.dashu.base.vo.DevicePicAddVO;
import com.dashu.base.vo.DevicePicDelReqVO;
import com.dashu.base.vo.DevicePicUpdReqVO;
import com.dashu.core.dto.company.CompanyDTO;
import com.dashu.core.dto.device.DeviceDTO;
import com.dashu.core.dto.device.DeviceListDTO;
import com.dashu.core.handler.VerificationException;
import com.dashu.core.model.Device;
import com.dashu.core.model.QDevice;
import com.dashu.core.result.PageEnty;
import com.dashu.core.vo.device.DeviceListVO;
import com.dashu.core.vo.device.DeviceVO;
import com.dashu.core.vo.UpdateEntityVO;
import com.dashu.core.vo.device.UpDeviceVO;
import com.querydsl.core.BooleanBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.FlushModeType;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DeviceService extends DataService {

    @Autowired
    private CompanyService companyService;

    @Transactional
    public DeviceDTO add(DeviceVO deviceVO) {
        Device device = CopyUtil.copyEnty(deviceVO, Device.class);
        try {
            long userId = Long.parseLong(VerificationUtil.getUserId());
            device.setId(UIDUtil.nextId());
            device.setCreateUser(userId);
            device.setCreateTime(System.currentTimeMillis());
            device.setDeviceType(DeviceType.map.get(deviceVO.getDeviceType()));
            device.setDoorType(Type.map.get(deviceVO.getDoorType()));
            device.setFunction(FunctionType.map.get(deviceVO.getFunction()));
            device.setInAndOut(ParkVdcType.map.get(deviceVO.getInAndOut()));
            device.setPosition(Position.map.get(deviceVO.getPosition()));
            device.setModuleType(ModuleType.SY);
            entityManager.persist(device);
//            entityManager.flush();
            entityManager.setFlushMode(FlushModeType.AUTO);
        } catch (Exception e) {
            e.printStackTrace();
            throw new VerificationException(ReplRyCode.DATA_NOT_INVALID, ReplRyCode.DATA_NOT_INVALID.getMessage());
        }
        DeviceDTO deviceDTO = CopyUtil.copyEnty(device, DeviceDTO.class);
        return deviceDTO;

    }

    @Transactional
    public boolean deleteByDeviceId(long DeviceId) {
        QDevice qDevice = QDevice.device;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.id.eq(DeviceId));
        Device device;

        queryFactory.select();
        device = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue()).fetchOne();
        if (device == null)
            throw new VerificationException(ReplRyCode.PERMISSION_NOT_DATA, ReplRyCode.PERMISSION_NOT_DATA.getMessage());
        entityManager.remove(device);
//            entityManager.flush();
        entityManager.setFlushMode(FlushModeType.AUTO);
        return true;

    }

    @Transactional
    public DeviceDTO updataByDeviceId(UpdateEntityVO<UpDeviceVO> updateEntityVO) throws Exception {
        QDevice qDevice = QDevice.device;
        long userId = Long.parseLong(VerificationUtil.getUserId());
        UpDeviceVO deviceVO = updateEntityVO.getEntityVO();
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.id.eq(updateEntityVO.getId()));
        Device device;
        try {
            device = queryFactory
                    .select(qDevice)
                    .from(qDevice)
                    .where(booleanBuilder.getValue()).fetchOne();
            if (deviceVO == null)
                return CopyUtil.copyEnty(device, DeviceDTO.class);
            if (!StringUtils.isEmpty(deviceVO.getDeviceName()))
                device.setDeviceName(deviceVO.getDeviceName());
            if (!StringUtils.isEmpty(deviceVO.getDeviceNum()))
                device.setDeviceNum(deviceVO.getDeviceNum());
            if (!StringUtils.isEmpty(deviceVO.getDevicePass()))
                device.setDevicePass(deviceVO.getDevicePass());
            if (!StringUtils.isEmpty(deviceVO.getPosition()))
                device.setPosition(Position.map.get(deviceVO.getPosition()));
            if (deviceVO.getPassageway() != 0)
                device.setPassageway(deviceVO.getPassageway());
            if (!StringUtils.isEmpty(deviceVO.getDeviceType()))
                device.setDeviceType(DeviceType.map.get(deviceVO.getDeviceType()));
            if (!StringUtils.isEmpty(deviceVO.getFunction()))
                device.setFunction(FunctionType.map.get(deviceVO.getFunction()));
            if (!StringUtils.isEmpty(deviceVO.getInAndOut()))
                device.setInAndOut(ParkVdcType.map.get(deviceVO.getInAndOut()));
            if (!StringUtils.isEmpty(deviceVO.getDoorType()))
                device.setDoorType(Type.map.get(deviceVO.getDoorType()));
            device.setUpdateUser(userId);
            device.setUpdateTime(new Date().getTime());
            device = entityManager.merge(device);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
//        entityManager.flush();
        entityManager.setFlushMode(FlushModeType.AUTO);
        DeviceDTO deviceDTO = CopyUtil.copyEnty(device, DeviceDTO.class);
        return deviceDTO;

    }

    public List<DeviceDTO> findByBaseId(PageEnty<Long> baseVo) {
        QDevice qDevice = QDevice.device;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.createUser.eq(baseVo.getBaseId()));
        List<Device> devices = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue())
                .fetch();
        List<DeviceDTO> recycleDTOS = CopyUtil.copyList(devices, DeviceDTO.class);
        return recycleDTOS;

    }


    public void DeldeviceBaseHand(long companyId, DevicePicDelReqVO devicePicDelReqVO) {
        List<Device> devices = deviceBaseId(companyId);
        devices.stream().forEach(ds -> {
            devicePicDelReqVO.setIp(ds.getIp());
            devicePicDelReqVO.setPort(String.valueOf(ds.getPort()));
            devicePicDelReqVO.setDeviceUUID(ds.getUuid());
            devicePicDelReqVO.setDeviceType(ds.getDeviceType());
            devicePicDelReqVO.setPass(ds.getDevicePass());
            restTemplate.postForLocation("http://dashu-device/dashu/device/delUser", devicePicDelReqVO);
        });

    }

    public void UpdeviceBaseHand(long companyId, DevicePicUpdReqVO devicePicUpdReqVO) {
        List<Device> devices = deviceBaseId(companyId);
        if (devices.size() == 0)
            throw new VerificationException(ReplRyCode.EXIST_BIND_DEVICE, ReplRyCode.EXIST_BIND_DEVICE.getMessage());
        devices.stream().forEach(ds -> {
            devicePicUpdReqVO.setIp(ds.getIp());
            devicePicUpdReqVO.setPort(String.valueOf(ds.getPort()));
            devicePicUpdReqVO.setDeviceUUID(ds.getUuid());
            devicePicUpdReqVO.setDeviceType(ds.getDeviceType());
            devicePicUpdReqVO.setPass(ds.getDevicePass());
            restTemplate.postForLocation("http://dashu-device/dashu/device/updUser", devicePicUpdReqVO);
        });

    }

    public void AdddeviceBaseHand(long companyId, DevicePicAddVO devicePicAddVO) {
        List<Device> devices = deviceBaseId(companyId);
        if (devices.size() == 0)
            throw new VerificationException(ReplRyCode.EXIST_BIND_DEVICE, ReplRyCode.EXIST_BIND_DEVICE.getMessage());
        devices.stream().forEach(ds -> {
            devicePicAddVO.setIp(ds.getIp());
            devicePicAddVO.setPort(String.valueOf(ds.getPort()));
            devicePicAddVO.setDeviceUUID(ds.getUuid());
            devicePicAddVO.setDeviceType(ds.getDeviceType());
            devicePicAddVO.setPass(ds.getDevicePass());
            restTemplate.postForLocation("http://dashu-device/dashu/device/establishUser", devicePicAddVO);

        });

    }


    public List<Device> deviceBaseId(long baseId) {
        QDevice qDevice = QDevice.device;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.deviceBaseId.eq(baseId));
        List<Device> devices = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue())
                .fetch();
        return devices;

    }

    public DeviceDTO findByDeviceId(long DeviceId) {
        QDevice qDevice = QDevice.device;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.id.eq(DeviceId));
        Device device = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue()).fetchOne();
        if (device == null)
            throw new VerificationException(ReplRyCode.PERMISSION_NOT_DATA, ReplRyCode.PERMISSION_NOT_DATA.getMessage());
        DeviceDTO deviceDTO = CopyUtil.copyEnty(device, DeviceDTO.class);
        return deviceDTO;

    }

    public List<DeviceDTO> existByDeviceName(DeviceVO deviceVO) throws Exception {
        QDevice qDevice = QDevice.device;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.deviceBaseId.eq(deviceVO.getDeviceBaseId()));
        List<Device> devices = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue())
                .fetch();
        if (devices == null) return null;
        if (devices.stream().filter(d -> d.getUuid().equals(deviceVO.getUuid())).collect(Collectors.toList()).size() > 0)
            throw new VerificationException(ReplRyCode.EXIST_DEVICE_UUID, ReplRyCode.EXIST_DEVICE_UUID.getMessage());
        if (devices.stream().filter(d -> d.getDeviceName().equals(deviceVO.getDeviceName())).collect(Collectors.toList()).size() > 0)
            throw new VerificationException(ReplRyCode.EXIST_DEVICE_NAME, ReplRyCode.EXIST_DEVICE_NAME.getMessage());
        if (devices.stream().filter(d -> d.getPassageway() == deviceVO.getPassageway() && d.getInAndOut().equals(deviceVO.getInAndOut())).collect(Collectors.toList()).size() > 0)
            throw new VerificationException(ReplRyCode.EXIST_DEVICE_TYPEID, ReplRyCode.EXIST_DEVICE_TYPEID.getMessage());
        List<DeviceDTO> deviceDTO = CopyUtil.copyList(devices, DeviceDTO.class);
        return deviceDTO;

    }

    public DeviceDTO DeviceName(String deviceName) {
        QDevice qDevice = QDevice.device;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qDevice.deviceName.eq(deviceName));
        Device device = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue()).fetchOne();
        if (device == null)
            throw new VerificationException(ReplRyCode.PERMISSION_NOT_DATA, ReplRyCode.PERMISSION_NOT_DATA.getMessage());
        DeviceDTO deviceDTO = CopyUtil.copyEnty(device, DeviceDTO.class);
        return deviceDTO;

    }

    public long deviceCount(PageEnty<DeviceListVO> deviceListPageEntyVO) throws Exception {
        QDevice qDevice = QDevice.device;
        long userId = Long.parseLong(VerificationUtil.getUserId());
        long baseId = deviceListPageEntyVO.getBaseId() == 0 ? userId : deviceListPageEntyVO.getBaseId();
        DeviceListVO deviceListVO = deviceListPageEntyVO.getVo();
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        if (admin != baseId)
            booleanBuilder.and(qDevice.createUser.eq(baseId));
        if (!StringUtils.isEmpty(deviceListVO.getPosition()))
            booleanBuilder.and(qDevice.position.eq(Position.map.get(deviceListVO.getPosition())));
        if (!StringUtils.isEmpty(deviceListVO.getInAndOut()))
            booleanBuilder.and(qDevice.inAndOut.eq(ParkVdcType.map.get(deviceListVO.getInAndOut())));
        long count = queryFactory
                .select(qDevice.count())
                .from(qDevice)
                .where(booleanBuilder.getValue())
                .fetchCount();

        return count;

    }

    public List<DeviceListDTO> findByDeviceList(PageEnty<DeviceListVO> deviceListPageEntyVO) throws Exception {
        QDevice qDevice = QDevice.device;
        long userId = Long.parseLong(VerificationUtil.getUserId());
        long baseId = deviceListPageEntyVO.getBaseId() == 0 ? userId : deviceListPageEntyVO.getBaseId();
        DeviceListVO deviceListVO = deviceListPageEntyVO.getVo();
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        if (admin != baseId)
            booleanBuilder.and(qDevice.createUser.eq(baseId));
        if (!StringUtils.isEmpty(deviceListVO.getPosition()))
            booleanBuilder.and(qDevice.position.eq(Position.map.get(deviceListVO.getPosition())));
        if (!StringUtils.isEmpty(deviceListVO.getInAndOut()))
            booleanBuilder.and(qDevice.inAndOut.eq(ParkVdcType.map.get(deviceListVO.getInAndOut())));
        if (!StringUtils.isEmpty(deviceListVO.getDeviceName()))
            booleanBuilder.and(qDevice.deviceName.like("%" + deviceListVO.getDeviceName() + "%"));
        List<Device> devices = queryFactory
                .select(qDevice)
                .from(qDevice)
                .where(booleanBuilder.getValue())
                .offset((deviceListPageEntyVO.getPage() - 1) * deviceListPageEntyVO.getNum())
                .limit(deviceListPageEntyVO.getNum())
                .orderBy(qDevice.createTime.desc())
                .fetch();
        List<DeviceListDTO> deviceListDTOS = CopyUtil.copyList(devices, DeviceListDTO.class);
        deviceListDTOS.stream().forEach(dd -> {
            CompanyDTO companyDTO = companyService.findByCompanyId(dd.getDeviceBaseId());
            dd.setCompanyName(companyDTO.getCompanyName());
        });
        deviceListDTOS.stream().forEach(ald -> {
            if (JedisUtil.hexists(RedisLiveKeyConstants.ON_LINE, ald.getUuid())) {
                ald.setStatus(DeviceOnline.ON_LINE.name);
            } else {
                ald.setStatus(DeviceOnline.OFF_LINE.name);
            }
        });
        return deviceListDTOS;

    }


}
